package server.command.ecs;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

import client.KVStore;
import app_kvClient.KVClient;
import app_kvServer.KVServer;
import server.command.client.ClientInputHandler;
import server.command.client.ICommand;
import utils.IKeyValueStorage;
import utils.SynchronizedAccessStorageUtil;
import common.messages.KVMessage;
import common.messages.KVMessage.StatusType;

public class CommandMoveData implements ICommand {
	private SynchronizedAccessStorageUtil storageUtil;
	private String rangeStart; 
	private String rangeEnd;
	private String serverIp;
	private int serverPort;
	
	public CommandMoveData(SynchronizedAccessStorageUtil storageUtil, String rangeStart, String rangeEnd, String serverIp, int serverPort) {
		this.storageUtil = storageUtil;
		this.rangeStart = rangeStart;
		this.rangeEnd = rangeEnd;
		this.serverIp = serverIp;
		this.serverPort = serverPort;
	}
	
	@Override
	public String execute() {
		/** Connect to the target server **/
		KVStore serverB = new KVStore(serverIp, serverPort, false);
		try {
			serverB.connect();
		} catch(Exception exc) {
			exc.printStackTrace();
		}
		/** Traverse all keys **/
		Set<String> keys = storageUtil.getKeysSet();
		ArrayList<String> keysToDelete = new ArrayList<String>();
		for (String key: keys) {
			/** If the key is within the range, move the entry to another server **/
			if (key.compareTo(rangeStart)>=0 && key.compareTo(rangeEnd)<=0) {
				try {
					int attemptsNum = 5;
					while (--attemptsNum>=0) {
						KVMessage resp = serverB.put(key, (String) storageUtil.get(key));
						if(resp.getStatus().equals(KVMessage.StatusType.PUT_SUCCESS)) {
							/** if succeeded, add them to the delete queue **/
							keysToDelete.add(key);
							break;
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		for (String keyToDelete: keysToDelete) {
			try {
				storageUtil.remove(keyToDelete);
			} catch (Exception exc) {
				
			}
		}
		/** Disconnect from the target server **/
		try {
			serverB.disconnect();
		} catch (Exception exc) {
			
		}
		return ClientInputHandler.composeClientResponse(StatusType.DATA_MOVED, " ", ""); 
	}
}
